/**
 * File HtmlDialog.java
 * ---------------------------------------------------------
 *
 * Copyright (C) 2012 David Bauske (david.bauske@googlemail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * - The origin of the software must not be misrepresented.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * TL;DR: As long as you clearly give me credit for this Software, you are free to use as you like, even in commercial software, but don't blame me
 * 		if it breaks something.
 */
package net.cl.util.ui;

import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;

/**
 * Represents a custom dialog window containing HTML-formatted text.
 *
 * @author David Bauske
 */
public class HtmlDialog extends JDialog
{
	private static final long		serialVersionUID		= -4858207622745810092L;
	private static final int		BORDER_SIZE				= 8;

	public static final int			DIALOG_CLOSED			= -1;

	public static final String[]	OPTION_OK				= { "OK" };
	public static final String[]	OPTION_OK_CANCEL		= { "OK", "Cancel" };
	public static final String[]	OPTION_YES_NO			= { "Yes", "No" };
	public static final String[]	OPTION_YES_NO_CANCEL	= { "Yes", "No", "Cancel" };

	private String[]				mOptions;
	private int						mChosenOption			= DIALOG_CLOSED;

	/**
	 * Creates a new Creator object, used to display an HtmlDialog in an easy way. Just call any methods on the creator
	 * you want and finally call show() to bring the window up.
	 *
	 * @param pParent The parent window of the dialog to be created.
	 * @param pMessage The message to display to the user. If null is passed, An IllegalArgumentException is thrown.
	 * @return The new Creator object.
	 * @throws IllegalArgumentException If pMessage is null.
	 */
	public static Creator creator(Window pParent, String pMessage)
	{
		return new Creator(pParent, pMessage);
	}

	/**
	 * Constructs a new HtmlDialog.
	 *
	 * @param pParent The parent component or null if the dialog has no parent.
	 * @param pMessage The message to display. HTML in this message will be displayed correctly.
	 * @param pTitle The dialog window's title.
	 * @param pIcon An icon to show on the left side of the dialog. Pass null to display a standart
	 *            information icon.
	 * @param pOptions A list of options the user can choose from. each option gets it's own button.
	 *            May be one of the OPTION_XXX constants from this class.
	 */
	public HtmlDialog(Window pParent, String pMessage, String pTitle, Icon pIcon,
			String... pOptions)
	{
		super(pParent, pTitle, Dialog.ModalityType.APPLICATION_MODAL);

		this.setLayout(new BorderLayout());

		if(pIcon == null)
		{
			pIcon = DefaultSwingIcon.INFO.getIcon();
		}

		HtmlTextPane htmlPane = new HtmlTextPane(pMessage);
		JScrollPane scroller = new JScrollPane(htmlPane);
		this.add(scroller, BorderLayout.CENTER);

		JLabel icon = new JLabel(pIcon);
		icon.setBorder(new EmptyBorder(0, BORDER_SIZE, 0, BORDER_SIZE));
		this.add(icon, BorderLayout.LINE_START);

		mOptions = pOptions;

		JPanel footPanel = new JPanel();
		int index = 0;
		for(String s : mOptions)
		{
			class IndexedButton extends JButton
			{
				private static final long	serialVersionUID	= 1L;
				private int					mOptionIndex		= 0;

				public IndexedButton(String s, int index)
				{
					super(s);
					this.mOptionIndex = index;
				}
			}

			IndexedButton btn = new IndexedButton(s, index);
			footPanel.add(btn);
			btn.addActionListener(new ActionListener()
			{
				@Override
				public void actionPerformed(ActionEvent event)
				{
					HtmlDialog.this.mChosenOption = ((IndexedButton) event.getSource()).mOptionIndex;
					HtmlDialog.this.setVisible(false);
				}
			});
			++index;
		}
		this.add(footPanel, BorderLayout.PAGE_END);
	}

	/**
	 * Builder class for a HtmlDialog. Makes bringing up a simple, modal and good looking dialog very easy.
	 *
	 * To obtain an instance of this class, use the {@link HtmlDialog#creator(Window, String)} Method.
	 */
	public static class Creator
	{
		protected Window	mParent		= null;
		protected String	mTitle		= "Message";
		protected String	mMessage	= null;
		protected Icon		mIcon		= DefaultSwingIcon.INFO.getIcon();
		protected String[]	mOptions	= OPTION_OK;
		protected int		mWidth		= -1;
		protected int		mHeight		= -1;
		protected boolean	mResizable	= true;

		protected Creator(Window pParent, String pMessage)
		{
			if(pMessage == null)
			{
				throw new IllegalArgumentException("pMessage may not be null.");
			}
			mParent = pParent;
			mMessage = pMessage;
		}

		/**
		 * Sets the title of this dialog (the text shown in the window's top border)
		 *
		 * @param pTitle The text to set
		 * @return <i>this</i> to allow for chaining.
		 */
		public Creator title(String pTitle)
		{
			this.mTitle = pTitle;
			return this;
		}

		/**
		 * Sets the icon of the HtmlDialog.
		 *
		 * @param pIcon The icon to display. May not be null.
		 * @return <i>this</i> to allow for chaining.
		 * @throws IllegalArgumentException if pIcon is null.
		 */
		public Creator icon(Icon pIcon)
		{
			if(pIcon == null)
			{
				throw new IllegalArgumentException("pIcon may not be null");
			}
			this.mIcon = pIcon;
			return this;
		}

		/**
		 * Sets the labels on the buttons that will be shown on the dialog.
		 *
		 * @param pOptions A number of options to show to the user. Passing null will result in no buttons being
		 *            displayed.
		 * @return <i>this</i> to allow for chaining.
		 */
		public Creator options(String... pOptions)
		{
			if(pOptions == null)
			{
				pOptions = new String[0];
			}
			this.mOptions = pOptions;
			return this;
		}

		/**
		 * Sets the dialog's size in pixels
		 *
		 * @param pWidth The width of the dialog. Pass -1 to have it calculated automatically.
		 * @param pHeight The height of the dialog. Pass -1 to have it calculated automatically.
		 * @return <i>this</i> to allow for chaining.
		 */
		public Creator size(int pWidth, int pHeight)
		{
			this.mWidth = pWidth;
			this.mHeight = pHeight;
			return this;
		}

		/**
		 * Sets whether or not the user will have the possibility to resize the dialog manually.
		 *
		 * @param pResizable <i>true</i> to allow manual resizing, <i>false</i> to disallow it.
		 * @return <i>this</i> to allow for chaining.
		 */
		public Creator resizable(boolean pResizable)
		{
			this.mResizable = pResizable;
			return this;
		}

		/**
		 * Finally shows the dialog.
		 *
		 * @return The index of the option the user chose in the array to close the window, or DIALOG_CLOSED if the user
		 *         clicked the window frame's close button.
		 */
		public int show()
		{
			HtmlDialog dialog = new HtmlDialog(this.mParent, this.mMessage, this.mTitle,
					this.mIcon, this.mOptions);

			if(mWidth < 0)
			{
				mWidth = (int) dialog.getPreferredSize().getWidth();
			}
			if(mHeight < 0)
			{
				mHeight = (int) dialog.getPreferredSize().getHeight();
			}

			dialog.setSize(mWidth, mHeight);
			dialog.setResizable(mResizable);
			if(this.mParent != null)
			{
				// Set the dialog's position relative to its parent's while making sure that the dialog will be fully
				// visible.

				// Compute the ideal position
				int posX = this.mParent.getX() + this.mParent.getWidth() / 2 - this.mWidth / 2;
				int posY = this.mParent.getY() + this.mParent.getHeight() / 2 - this.mHeight / 2;

				// Ensure that the bottom and right side of the dialog are viisble.
				Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
				posX = Math.min(posX, (int) screenSize.getWidth()
						- this.mWidth);
				posY = Math.min(posY, (int) screenSize.getHeight()
						- this.mHeight);

				// Ensure that the top and left side of the dialog are visible.
				posX = Math.max(posX, 0);
				posY = Math.max(posY, 0);

				dialog.setLocation(posX, posY);
			}

			dialog.setVisible(true); // Brings the dialog up. Blocking call.
			dialog.dispose();
			return dialog.mChosenOption;
		}
	}
}
